<!-- eslint-disable prettier/prettier -->
<script setup lang="ts">
import { ref, watch } from "vue"
import { Node, Edge, NodeChange, Position, VueFlow, useVueFlow, NodeMouseEvent } from "@vue-flow/core"
import { MiniMap } from "@vue-flow/minimap"
import { ElMessage, ElMessageBox } from "element-plus"
import useDragAndDrop from "@@/composables/useDragAndDrop"
import { Sidebar, DropzoneBackground, CustomNodeOutput, CustomNodeInput } from "./index"
import { generateAgent } from "@@/apis/agent-dev"
import { GenerateAgentData } from "@@/apis/agent-dev/types"
import { getProjectId } from "@/common/utils/cache/local-storage"
import { closeRoute } from "@/common/composables/useCloseRouteListener"
const emit = defineEmits(["handleGenerated", "handleCancel"])

const { onInit, onConnect, addEdges, onNodesChange, applyNodeChanges } = useVueFlow()
const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop()

const nodes = ref<Node[]>([
  {
    id: "1",
    type: "input",
    data: { label: "智能体", value: "", code: 'Agent' },
    position: { x: 250, y: 0 },
    class: "light",
    sourcePosition: Position.Right
  }
])
const edges = ref<Edge[]>([])
const dark = ref(false)
const genLoading = ref(false)
const nowNodeId = ref<string | undefined>(undefined)

onInit((vueFlowInstance) => {
  vueFlowInstance.fitView({ maxZoom: 1.5 })
})

onConnect((connection) => {
  addEdges(connection)
})

onNodesChange(async (changes: NodeChange[]) => {
  const nextChanges: NodeChange[] = []
  for (const change of changes) {
    if (change.type === "remove") {
      if (change.id == "1") {
        ElMessage.warning("不可以删除该节点！")
        return
      }
      const isConfirmed = await dialogMsg(change.id)

      if (isConfirmed) {
        nextChanges.push(change)
      }
    } else {
      nextChanges.push(change)
    }
  }
  applyNodeChanges(nextChanges)
})

function dialogMsg(id: string) {
  return new Promise((resolve) => {
    ElMessageBox.confirm(`确定是否要删除节点${id}？`, "提示", {
      confirmButtonText: "删除",
      cancelButtonText: "取消",
      type: "warning"
    })
      .then(() => {
        resolve(true)
      })
      .catch(() => {
        resolve(false)
      })
  })
}
const handleGenerate = () => {
  genLoading.value = true
  const associate_id = getProjectId()
  const params: GenerateAgentData = {
    agent_name: "",
    agent_code: "",
    algorithms: [],
    ...(getProjectId() ? { project_id: getProjectId() } : {})
  }
  nodes.value.forEach((item) => {
    if (item.id == "1") {
      params.agent_name = item.data.value
      params.agent_code = item.data.code
    } else {
      params.algorithms.push({
        algorithm_name: item.data.algo,
        component_name: item.data.value
      })
    }
  })
  generateAgent(associate_id, params)
    .then(({ data }) => {
      emit("handleGenerated", { agentId: data.agent_id, agentName: params.agent_name})
    })
    .finally(() => {
      genLoading.value = false
    })
}
const onDropOver = (event: DragEvent) => {
  onDrop(event)
}

const onNodeClick = (event: NodeMouseEvent) => {
  const { node } = event
  if (node.type == "output") {
    nowNodeId.value = node.id
  }
}
const handleCancel = () => {
  closeRoute()
}

function onDragStop(event: NodeMouseEvent) {
  const { node } = event
  if (node.type == "output") {
    nowNodeId.value = node.id
  }
}

watch(
  () => nodes.value,
  () => {
    edges.value = []
    nodes.value.forEach((item) => {
      if (item.id != "1") {
        edges.value.push({
          id: `edge-1-${item.id}`,
          source: "1",
          target: item.id
        })
      }
    })
  }
)
</script>

<template>
  <div class="generate-wrapper">
    <div class="cpi-header">
      <span class="cpi-header-text">新建智能体</span>
      <div class="cpi-header-operate">
        <el-button type="primary" @click="handleGenerate">生成</el-button>
        <el-button @click="handleCancel">取消</el-button>
      </div>
    </div>
    <div class="cpi-content">
      <div class="dnd-flow" @drop="onDropOver">
        <Sidebar :id="nowNodeId" />
        <VueFlow v-model:nodes="nodes" :edges="edges" :class="{ dark }" :apply-default="false" class="basic-flow"
          @node-drag-stop="onDragStop" @dragover="onDragOver" @dragleave="onDragLeave" @node-click="onNodeClick">
          <DropzoneBackground :style="{
            backgroundColor: isDragOver ? '#001b44' : 'transparent',
            transition: 'background-color 0.2s ease'
          }">
            <p v-if="isDragOver">拖拽到这里</p>
          </DropzoneBackground>
          <template #node-input="props">
            <CustomNodeInput :id="props.id" :data="props.data" />
          </template>
          <template #node-output="props">
            <CustomNodeOutput :id="props.id" :data="props.data" />
          </template>
          <MiniMap />
        </VueFlow>
      </div>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.cpi-content {
  flex: 1;
}

.generate-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.vue-flow__minimap {
  transform: scale(75%);
  transform-origin: bottom right;
}

.dnd-flow {
  width: 100%;
  height: calc(100%);
  position: relative;
}

.dnd-flow .vue-flow-wrapper {
  flex-grow: 1;
  height: 100%;
}

@media screen and (min-width: 640px) {
  .dnd-flow {
    flex-direction: row;
  }
}

.dropzone-background {
  position: relative;
  height: 100%;
  width: 100%;
}

:deep(.vue-flow__node-input) {
  background: #2B3D6C !important;
  background-color: #2B3D6C !important;
  padding: 6px;
  color: white;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  border-color: transparent;
}

:deep(.vue-flow__node-output) {
  background: #2B3D6C !important;
  background-color: #2B3D6C !important;
  padding: 6px;
  color: white;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  border-color: transparent;
}

.vue-flow__node-value input {
  flex: 1;
  padding: 8px;
  border: none;
  border-radius: 8px;
  box-shadow: 0 0 10px #0000001a
}

:deep(.vue-flow__node-default.selected),
:deep(.vue-flow__node-default.selected:hover),
:deep(.vue-flow__node-output.selected),
:deep(.vue-flow__node-output.selected:hover),
:deep(.vue-flow__node-output:focus),
:deep(.vue-flow__node-output:focus-visible),
:deep(.vue-flow__node-default:focus),
:deep(.vue-flow__node-default:focus-visible) {
  border: 1px solid #409EFF;
  border-color: #409EFF;
  box-shadow: 0 0 0 0.5px #409EFF;
}
</style>
